﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace AsmResolver.PE.Win32Resources.String
{
    public class StringEntry : DataSegment
    {

        public ushort LanguageIdentifier
        {
            get;
            set;
        }
        public ushort CodePage
        {
            get;
            set;
        }
        public StringEntry(ushort languageIdentifier, ushort codePage) : base(null)
        {
            LanguageIdentifier = languageIdentifier;
            CodePage = codePage;
        }

        public StringEntry(byte[] data) : base(data) { }

        private readonly IDictionary<uint, string> _entries = new Dictionary<uint, string>();
        public IDictionary<uint, string> Entries
        {
            get => _entries;
        }

        public static StringEntry FromReader(IBinaryStreamReader reader, uint Id, ushort codePage)
        {
            uint start = reader.FileOffset;

            var result = new StringEntry(0, codePage);
            var i = 0;
            while (reader.FileOffset - start < reader.Length)
            {
                ushort len = reader.ReadUInt16();
                byte[] bytes = new byte[len * 2];
                reader.ReadBytes(bytes, 0, len * 2);
                var value = Encoding.Unicode.GetString(bytes);
                uint id = (uint)(((Id - 1) << 4) + i);
                result.Add(id, value);
                i++;
            }
            return result;
        }

        public string this[uint key]
        {
            get => _entries[key];
            set
            {
                if (value is null)
                    _entries.Remove(key);
                else
                    _entries[key] = value;
            }
        }
        public void Add(uint key, string value) =>
            _entries[key] = value ?? throw new ArgumentNullException(nameof(value));

        public bool Remove(uint key) => _entries.Remove(key);
        public override uint GetPhysicalSize()
        {
            uint size = 0;
            foreach (var v in _entries.Values)
            {
                size += (uint)(sizeof(ushort) + v.Length * 2);
            }
            return size;
        }

        public override void Write(IBinaryStreamWriter writer)
        {
            var stream = new MemoryStream();
            var bw = new BinaryStreamWriter(stream);
            foreach (var v in _entries.Values)
            {
                bw.WriteInt16((short)v.Length);
                var bytes = Encoding.Unicode.GetBytes(v);
                bw.WriteBytes(bytes);
            }
            Data = new byte[stream.Length];
            stream.Seek(0, SeekOrigin.Begin);
            stream.Read(Data, 0, Data.Length);

            base.Write(writer);
        }
    }
}
